package cn.wwcyc.dao;


import cn.wwcyc.exception.WWException;
import cn.wwcyc.exception.WWExceptionEnum;
import com.serotonin.modbus4j.BatchRead;
import com.serotonin.modbus4j.BatchResults;
import com.serotonin.modbus4j.ModbusFactory;
import com.serotonin.modbus4j.ModbusMaster;
import com.serotonin.modbus4j.code.DataType;
import com.serotonin.modbus4j.exception.ErrorResponseException;
import com.serotonin.modbus4j.exception.ModbusInitException;
import com.serotonin.modbus4j.exception.ModbusTransportException;
import com.serotonin.modbus4j.ip.IpParameters;
import com.serotonin.modbus4j.locator.BaseLocator;
import com.serotonin.modbus4j.msg.*;
import com.sun.prism.PixelFormat;
import org.bouncycastle.math.raw.Mod;
import org.springframework.stereotype.Repository;

@Repository
public class ModbusDao {
    static ModbusFactory modbusFactory;

    static {
        if (modbusFactory == null) {
            modbusFactory = new ModbusFactory();
        }
    }

    public static ModbusMaster getMaster(String ip) throws ModbusInitException {
        IpParameters params = new IpParameters();
        params.setHost(ip);
        params.setPort(502);
        //
        // modbusFactory.createRtuMaster(wapper); //RTU 协议
        // modbusFactory.createUdpMaster(params);//UDP 协议
        // modbusFactory.createAsciiMaster(wrapper);//ASCII 协议
        ModbusMaster master = modbusFactory.createTcpMaster(params, false);// TCP 协议
        master.init();
        master.setTimeout(3000);
//      master.destroy();
        return master;
    }

    //功能码01 读取线圈状态
    public static Boolean readCoilStatus(String ip, int slaveId, int offset)
            throws ModbusTransportException, ErrorResponseException, ModbusInitException {
        // 01 Coil Status
        BaseLocator<Boolean> loc = BaseLocator.coilStatus(slaveId, offset);
        Boolean value = getMaster(ip).getValue(loc);
        return value;
    }

    //功能码02 读取输入状态
    public static Boolean readInputStatus(String ip, int slaveId, int offset)
            throws ModbusTransportException, ErrorResponseException, ModbusInitException {
        // 02 Input Status
        BaseLocator<Boolean> loc = BaseLocator.inputStatus(slaveId, offset);
        Boolean value = getMaster(ip).getValue(loc);
        return value;
    }

    //功能码03 读取holdingregister
    public static Number readHoldingRegister(String ip, int slaveId, int offset, int datatype)
            throws ModbusTransportException, ErrorResponseException, ModbusInitException {
        BaseLocator<Number> loc = BaseLocator.holdingRegister(slaveId, offset, datatype);
        Number value = getMaster(ip).getValue(loc);
        return value;
    }

    //功能码04 读取Inputregister
    public static Number readInputRegister(String ip, int slaveId, int offset, int datatype)
            throws ModbusTransportException, ErrorResponseException, ModbusInitException {
        BaseLocator<Number> loc = BaseLocator.inputRegister(slaveId, offset, datatype);
        Number value = getMaster(ip).getValue(loc);
        return value;
    }

    //批量读，测试方法
    public static void batchRead(String ip, int slaveId)
            throws ModbusTransportException, ErrorResponseException, ModbusInitException {
        BatchRead<Integer> batch = new BatchRead<Integer>();
        batch.addLocator(1, BaseLocator.holdingRegister(slaveId, 0, DataType.TWO_BYTE_INT_SIGNED));
        batch.addLocator(2, BaseLocator.holdingRegister(slaveId, 1, DataType.TWO_BYTE_INT_SIGNED));
        batch.setContiguousRequests(false);
        ModbusMaster master = getMaster(ip);
        BatchResults<Integer> response = master.send(batch);
        System.out.println(response.getValue(1));
        System.out.println(response.getValue(2));
    }

    //功能码05 写入单个线圈
    public static void setCoilStatus(String ip, int slaveId, int offset, Boolean b)
            throws ModbusTransportException, ErrorResponseException, ModbusInitException {
        // 01 Coil Status
        BaseLocator<Boolean> loc = BaseLocator.coilStatus(slaveId, offset);
        getMaster(ip).setValue(loc, b);
    }

    //功能码15 写入多个线圈
    public static void setCoilStatus(String ip, int slaveId, int offset, boolean[] b)
            throws ModbusTransportException, ErrorResponseException, ModbusInitException {
        ModbusMaster master = getMaster(ip);
        WriteCoilsRequest request = new WriteCoilsRequest(slaveId, offset, b);
        ModbusResponse response = master.send(request);
        if (response instanceof ExceptionResponse) {
            throw new WWException(WWExceptionEnum.MODBUS_ERROR);
        }
    }

    //功能吗6  写保持寄存器
    public static boolean writeSingleRegister(String ip, int slaveId, int offset, short sdata)
            throws ModbusInitException, ModbusTransportException {
        ModbusMaster modbusMaster = getMaster(ip);
        WriteRegisterRequest writeRegisterRequest = new WriteRegisterRequest(slaveId, offset, sdata);
        ModbusResponse response = modbusMaster.send(writeRegisterRequest);
        if (response.isException()) {
            throw new WWException(WWExceptionEnum.MODBUS_ERROR);
        }
        return true;
    }

    //功能吗16 写入多保持个寄存器
    public static boolean writeHoldingRegisters(String ip, int slaveId, int offset, short[] sdata)
            throws ModbusInitException, ModbusTransportException {
        ModbusMaster modbusMaster = getMaster(ip);
        WriteRegistersRequest writeRegisterRequest = new WriteRegistersRequest(slaveId, offset, sdata);
        ModbusResponse response = modbusMaster.send(writeRegisterRequest);
        if (response.isException()) {
            throw new WWException(WWExceptionEnum.MODBUS_ERROR);
        }
        return true;
    }

    //写入Number的子类，如int，long，short，float, double
    public static void setHoldingRegister(String ip, int slaveId, int offset,int datatype, Number value)
            throws ModbusInitException, ModbusTransportException, ErrorResponseException {
        //DataType.TWO_BYTE_INT_UNSIGNED 2;
        //DataType.TWO_BYTE_INT_SIGNED 3;
//        DataType.FOUR_BYTE_INT_SIGNED 5;
//        DataType.FOUR_BYTE_INT_UNSIGNED 4;
        //DataType.FOUR_BYTE_FLOAT 8;
//        DataType.FOUR_BYTE_FLOAT_INVERTED
//        DataType.FOUR_BYTE_INT_SIGNED_SWAPPED 7;
        // DataType.EIGHT_BYTE_FLOAT 14;
//        DataType.TWO_BYTE_INT_UNSIGNED
        System.out.println("setHoldingRegister" + ip + "--slaveId:" + slaveId + "--offset:" + offset + "--datatype:" + datatype);
        BaseLocator<Number> loc = BaseLocator.holdingRegister(slaveId, offset, datatype);
        getMaster(ip).setValue(loc, value);
    }

    //    public static Number readHoldingRegister(String ip, int slaveId, int offset, int datatype)
//            throws ModbusTransportException, ErrorResponseException, ModbusInitException {
//        BaseLocator<Number> loc = BaseLocator.holdingRegister(slaveId, offset, datatype);
//        Number value = getMaster(ip).getValue(loc);
//        return value;
//    }
    public static void main(String[] args) throws ModbusInitException, ModbusTransportException, ErrorResponseException {

        ModbusDao.setHoldingRegister("127.0.0.1", 1, 0, 123, DataType.TWO_BYTE_INT_UNSIGNED_SWAPPED);
        Number value = ModbusDao.readHoldingRegister("127.0.0.1", 1, 0, DataType.TWO_BYTE_INT_UNSIGNED_SWAPPED);
        System.out.println(value);

    }
}
